﻿#include "businessgroup.h"
#include "businesssql.h"
#include "businessnetwork.h"
#include <protocol/protocolConverter.h>
#include<Debug/DEBUG.hpp>

BusinessGroup::BusinessGroup() {}

bool BusinessGroup::checkGroup(const std::string &groupName)
{
    return BusinessSQL::getInstance().queryAGroupExists(groupName);
}

void BusinessGroup::recvCreateGroupRequest(std::shared_ptr<Protocol> protocol, const hv::SocketChannelPtr &channel)
{
    ProtocolConverter converter;
    converter.setProtocolOption(BusinessNetWork::getInstance().getProtocolOption());
    converter.parseData((unsigned char*)protocol->data());


    std::string groupName;
    groupName.resize(converter.getParsedDataSize(), '\0');
    converter.copyParsedData((void*) groupName.data());


    uint64_t point = std::get<int64_t>(converter.getHeaderField(4));

    BusinessNetWork& net = BusinessNetWork::getInstance();
    // check if groupName is valid

    if (groupName.empty() || checkGroup(groupName)) {
        // exist or empty group name, reject
        net.sendMessageToClient(channel,
                                4,4,0,0,point,
                                nullptr, 0);
        return ;
    }


    uint64_t applyID = std::get<int64_t>(converter.getHeaderField(2));

    // create group success
    BusinessSQL& sql = BusinessSQL::getInstance();

    sql.createAGroup(groupName, applyID);
    uint64_t groupID = getGroupID(groupName);
    sql.joinAGroup(groupID, applyID, "member");

    net.sendMessageToClient(channel,
                            4,3,0,0,point,
                            nullptr, 0);

}

void BusinessGroup::recvUpdateGroupList(std::shared_ptr<Protocol> protocol, const hv::SocketChannelPtr &channel)
{
    ProtocolConverter converter;
    converter.setProtocolOption(BusinessNetWork::getInstance().getProtocolOption());
    converter.parseData((unsigned char*)protocol->data());

    std::string account;
    account.resize(converter.getParsedDataSize(), '\0');
    converter.copyParsedData((void*) account.data());

    updateGroupList(account, channel);
}

void BusinessGroup::updateGroupList(const std::string &account, const hv::SocketChannelPtr &channel)
{
    nlohmann::json groupJson = BusinessSQL::getInstance().findUserGroupsAndPosition(account);
    std::string groupStr = groupJson.dump();

    BusinessNetWork::getInstance().sendMessageToClient(channel,
                                                       6, 6, 0, 0, 0,
                                                       (unsigned char *)groupStr.c_str(), groupStr.size());
}

void BusinessGroup::recvJoinGroupRequest(std::shared_ptr<Protocol> protocol, const hv::SocketChannelPtr &channel)
{
    ProtocolConverter converter;
    converter.setProtocolOption(BusinessNetWork::getInstance().getProtocolOption());
    converter.parseData((unsigned char*)protocol->data());
    BusinessSQL& sql = BusinessSQL::getInstance();
    // get userID
    uint64_t userID = std::get<int64_t>(converter.getHeaderField(2));
    // get groupName
    std::string groupName;
    groupName.resize(converter.getParsedDataSize(), '\0');
    converter.copyParsedData((void*) groupName.data());
    // get syncPoint
    uint64_t syncPoint = std::get<int64_t>(converter.getHeaderField(4));

    // check groupName if valid
    bool ret = sql.queryAGroupExists(groupName);
    BusinessNetWork& net = BusinessNetWork::getInstance();
    if (ret) {
        // exist, join to the group
        // get groupID
        uint64_t groupID = getGroupID(groupName);
        BusinessSQL::getInstance().joinAGroup(groupID, userID, "pending");
        net.sendMessageToClient(channel, 4, 3, 0, 0, syncPoint,
                                nullptr, 0);
    } else {
        // not exist
        net.sendMessageToClient(channel, 4, 4, 0, 0, syncPoint,
                                nullptr, 0);
    }
}

uint64_t BusinessGroup::getGroupID(const std::string &groupName)
{
    if (groupInfoStore.count(groupName)) {
        return groupInfoStore[groupName];
    }

    nlohmann::json info = BusinessSQL::getInstance().queryAGroupInfo(groupName);
    groupInfoStore[groupName] = info["GroupID"];
    return info["GroupID"];
}

void BusinessGroup::recvGroupMessage(std::shared_ptr<Protocol> protocol, const hv::SocketChannelPtr &channel)
{
    ProtocolConverter converter;
    converter.setProtocolOption(BusinessNetWork::getInstance().getProtocolOption());
    converter.parseData((unsigned char*)protocol->data());

    uint64_t userID = std::get<int64_t>(converter.getHeaderField(2));
    uint64_t groupID = std::get<int64_t>(converter.getHeaderField(3));

    std::string Tmessage;
    Tmessage.resize(converter.getParsedDataSize(), '\0');
    converter.copyParsedData((void*) Tmessage.data());
    nlohmann::json message = nlohmann::json::parse(Tmessage);

    std::string messageStr = message["Message"];
    int messageType = message["MessageType"];

    BusinessSQL& sql = BusinessSQL::getInstance();
    BusinessNetWork& net = BusinessNetWork::getInstance();
    // redirect to online user
    nlohmann::json users = sql.getGroupMember(groupID);
    DEBUG_INFO("group users");
    DEBUG_INFO(users.dump());
    // store to database
    auto messageInfo = sql.storeGroupMessage(userID, groupID, messageStr, messageType);

    nlohmann::json messageJson;
    messageJson["Message"] = messageStr;
    messageJson["MessageID"] = messageInfo.first;
    messageJson["Time"] = messageInfo.second;
    messageJson["MessageType"] = messageType;

    std::string sendStr = messageJson.dump();
    for (auto& user : users) {
        uint64_t targetUserID = user["UserID"];
        DEBUG_INFO("send message to :" + std::to_string((uint64_t)user["UserID"]));
        if (net.checkTargetUserOnline(targetUserID)) {
            // send message to user
            auto channel = net.getChannel(targetUserID);
            net.sendMessageToClient(channel,
                                    1,2,userID, groupID, 0,
                                    (unsigned char*)sendStr.c_str(), sendStr.size());
        }
    }

}

void BusinessGroup::recvLeaveGroup(std::shared_ptr<Protocol> protocol, const hv::SocketChannelPtr &channel)
{
    ProtocolConverter converter;
    converter.setProtocolOption(BusinessNetWork::getInstance().getProtocolOption());
    converter.parseData((unsigned char*)protocol->data());

    uint64_t userID = std::get<int64_t>(converter.getHeaderField(2));

    std::string groupName;
    groupName.resize(converter.getParsedDataSize(), '\0');
    converter.copyParsedData((void*) groupName.data());

    BusinessSQL& sql = BusinessSQL::getInstance();
    nlohmann::json groupInfo = sql.queryAGroupInfo(groupName);

    uint64_t groupOwnerID = groupInfo["OwnerID"];
    uint64_t groupID = groupInfo["GroupID"];
    if (groupOwnerID == userID) {
        // delete the group
        sql.deleteGroup(groupID);
    } else {
        // quit the group
        sql.userLeaveGroup(groupID, userID);
    }

}

void BusinessGroup::recvReplyOfGroupApply(std::shared_ptr<Protocol> protocol, const hv::SocketChannelPtr &channel)
{
    ProtocolConverter converter;
    converter.setProtocolOption(BusinessNetWork::getInstance().getProtocolOption());
    converter.parseData((unsigned char*)protocol->data());

    int subType = std::get<int64_t>(converter.getHeaderField(1));

    uint64_t userID = std::get<int64_t>(converter.getHeaderField(2));
    uint64_t groupID = std::get<int64_t>(converter.getHeaderField(3));

    BusinessSQL& sql = BusinessSQL::getInstance();
    if (subType == 14) {
        //accept
        sql.acceptUserJoinGroupRequest(groupID, userID);
    } else {
        sql.rejectUserJoinGroupRequest(groupID, userID);
    }

}

void BusinessGroup::recvUpdateGroupRequestList(std::shared_ptr<Protocol> protocol, const hv::SocketChannelPtr &channel)
{
    ProtocolConverter converter;
    converter.setProtocolOption(BusinessNetWork::getInstance().getProtocolOption());
    converter.parseData((unsigned char*)protocol->data());

    std::string account;
    account.resize(converter.getParsedDataSize(), '\0');
    converter.copyParsedData((void*) account.data());

    updateGroupRequestList(account, channel);
}

void BusinessGroup::updateGroupRequestList(const std::string &account, const hv::SocketChannelPtr &channel)
{
    nlohmann::json groupRequestJson = BusinessSQL::getInstance().getAllGroupRequest(account);
    std::string groupRequestStr = groupRequestJson.dump();

    BusinessNetWork::getInstance().sendMessageToClient(channel,
                                                       6, 7, 0, 0, 0,
                                                       (unsigned char*)groupRequestStr.c_str(), groupRequestStr.size());
}


